
package com.plian.system.service.pm.property.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.plian.Tools.*;
import com.plian.Tools.pagedata.PageData;
import com.plian.system.constant.sys.FormStatusConstant;
import com.plian.system.constant.sys.FormTypeConstant;
import com.plian.system.constant.yth.YthConstant;
import com.plian.system.dao.pm.property.PropertyRecordDao;
import com.plian.system.dto.pm.property.PropertyInfoDTO;
import com.plian.system.entity.pm.property.*;
import com.plian.system.entity.sys.Org;
import com.plian.system.mapper.pm.property.PropertyOutMapper;
import com.plian.system.model.page.Page;
import com.plian.system.properties.GzwProperties;
import com.plian.system.service.pm.property.*;
import com.plian.system.service.sys.file.FileService;
import com.plian.system.service.sys.orgzation.IOrgService;
import com.plian.system.service.transfer.ITransferFlowService;
import com.plian.system.vo.yth.YthResult;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 *  服务实现类
 *
 * @author jianglei
 * @since 2019-12-05
 */
@Slf4j
@Service
@AllArgsConstructor
public class PropertyOutServiceImpl extends ServiceImpl<PropertyOutMapper, PropertyOut> implements IPropertyOutService {

    private IPropertyBasicsService propertyBasicsService;

    private IContributorBasicsService contributorBasicsService;

    private IShareholdingBasicsService shareholdingBasicsService;

    private IPartnerOutboundBasicsService partnerOutboundBasicsService;

    private IPartnerSituationBasicsService partnerSituationBasicsService;

    private IPropertyRecordService propertyRecordService;

    private IContributorRecordService contributorRecordService;

    private IShareholdingRecordService shareholdingRecordService;

    private IPartnerOutboundRecordService partnerOutboundRecordService;

    private IPartnerSituationRecordService partnerSituationRecordService;

    private PropertyRecordDao propertyRecordDao;

    private ITransferFlowService transferFlowService;

    private GzwProperties gzwProperties;

    private IOrgService orgService;

    private FileService fileService;
    
    @Override
    public String checkList(PropertyInfoDTO propertyInfoDTO, String competentOrganization) {
        List<PropertyOut> propertyOutList = propertyInfoDTO.getPropertyOutList();
        if (CollectionUtil.isEmpty(propertyOutList)){
            return "数据为空";
        }

        List<PropertyBasics> existPropertyList = propertyBasicsService.list(new LambdaQueryWrapper<PropertyBasics>()
                .eq(PropertyBasics::getStatus, FormStatusConstant.FINISH)
                .eq(PropertyBasics::getCompetentOrganization, competentOrganization));
        List<String> existProIds = Optional.ofNullable(existPropertyList).orElse(new ArrayList<>()).stream().map(PropertyBasics::getId).collect(Collectors.toList());

        StringBuilder message = new StringBuilder();
        for (PropertyOut propertyOut : propertyOutList){
            String proId = propertyOut.getInitialId();
            if (!existProIds.contains(proId)){
                if (message.length() > 0){
                    message.append(",");
                }
                message.append("proId = " + proId + "在最新记录表中不存在");
                continue;
            }
        }
        return message.toString();
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public boolean saveList(PropertyInfoDTO propertyInfoDTO) {
        List<PropertyOut> propertyOutList = propertyInfoDTO.getPropertyOutList();

        List<PropertyRecord> propertyRecordList = new ArrayList<>();
        List<ContributorRecord> contributorRecordList = new ArrayList<>();
        List<ShareholdingRecord> shareholdingRecordList = new ArrayList<>();
        List<PartnerOutboundRecord> partnerOutboundRecordList = new ArrayList<>();
        List<PartnerSituationRecord> partnerSituationRecordList = new ArrayList<>();
        List<String> initialIds  = new ArrayList<>();

        String tokenUserId = TokenUtil.getTokenUserId();
        for (PropertyOut propertyOut : propertyOutList){
            propertyOut.setDataSource(tokenUserId);
            if (propertyOut.getUpdateTime() == null){
                propertyOut.setUpdateTime(propertyOut.getCreateTime());
            }
            propertyOut.setStatus(String.valueOf(FormStatusConstant.FINISH));
            propertyOut.setFormType(String.valueOf(FormTypeConstant.PM_PROPERTYOUT_FORM));
            PropertyBasics propertyBasics = propertyBasicsService.getById(propertyOut.getInitialId());

            String initialId = propertyBasics.getId();
            initialIds.add(initialId);
            String recordId = propertyOut.getId();
            String nature = propertyBasics.getNature();

            PropertyRecord propertyRecord = new PropertyRecord();
            BeanUtils.copyProperties(propertyBasics, propertyRecord);
            propertyRecord.setId(recordId);
            propertyRecord.setInitialId(initialId);
            propertyRecord.setStatus("4");
            propertyRecord.setOutId(propertyOut.getId());
            propertyRecord.setCreateTime(propertyOut.getCreateTime());
            propertyRecord.setUpdateTime(propertyOut.getUpdateTime());
            propertyRecord.setBsDate(propertyOut.getAicBsDate());
            propertyRecord.setAicBsDate(propertyOut.getAicBsDate());
            propertyRecordList.add(propertyRecord);

            propertyOut.setProId(recordId);

            contributorRecordList.addAll(Optional.ofNullable(contributorBasicsService.findByPropertyId(initialId))
                    .orElse(new ArrayList<>()).stream().map(contributorBasics -> {
                        ContributorRecord contributorRecord = new ContributorRecord();
                        BeanUtils.copyProperties(contributorBasics, contributorRecord);
                        contributorRecord.setPropertyId(recordId);
                        contributorRecord.setId(UuidUtil.get32UUID());
                        return contributorRecord;
                    }).collect(Collectors.toList()));
            switch (nature){
                case "1":
                    shareholdingRecordList.addAll(Optional.ofNullable(shareholdingBasicsService.findByPropertyId(initialId))
                            .orElse(new ArrayList<>()).stream().map(shareholdingBasics -> {
                                ShareholdingRecord shareholdingRecord = new ShareholdingRecord();
                                BeanUtils.copyProperties(shareholdingBasics, shareholdingRecord);
                                shareholdingRecord.setPropertyId(recordId);
                                shareholdingRecord.setId(UuidUtil.get32UUID());
                                return shareholdingRecord;
                            }).collect(Collectors.toList()));
                    break;
                case "2":
                    partnerOutboundRecordList.addAll(Optional.ofNullable(partnerOutboundBasicsService.findByPropertyId(initialId))
                            .orElse(new ArrayList<>()).stream().map(partnerOutbound -> {
                        PartnerOutboundRecord partnerOutboundRecord = new PartnerOutboundRecord();
                        BeanUtils.copyProperties(partnerOutbound, partnerOutboundRecord);
                        partnerOutboundRecord.setId(UuidUtil.get32UUID());
                        partnerOutboundRecord.setPropertyId(recordId);
                        return partnerOutboundRecord;
                    }).collect(Collectors.toList()));
                    partnerSituationRecordList.addAll(Optional.ofNullable(partnerSituationBasicsService.findByPropertyId(initialId))
                            .orElse(new ArrayList<>()).stream().map(partnerSituation -> {
                                PartnerSituationRecord partnerSituationRecord = new PartnerSituationRecord();
                                BeanUtils.copyProperties(partnerSituation, partnerSituationRecord);
                                partnerSituationRecord.setId(UuidUtil.get32UUID());
                                partnerSituationRecord.setPropertyId(recordId);
                                return partnerSituationRecord;
                            }).collect(Collectors.toList()));
                    break;
                default:
                    break;
            }
        }

        boolean result = saveBatch(propertyOutList);
        propertyRecordService.saveBatch(propertyRecordList);
        contributorRecordService.saveBatch(contributorRecordList);
        shareholdingRecordService.saveBatch(shareholdingRecordList);
        partnerOutboundRecordService.saveBatch(partnerOutboundRecordList);
        partnerSituationRecordService.saveBatch(partnerSituationRecordList);
        propertyBasicsService.updateStatus(initialIds, "4");
        return result;
    }

    @Override
    public String unitCheckList(PropertyInfoDTO propertyInfoDTO, String competentOrganization) {
        List<PropertyOut> propertyOutList = propertyInfoDTO.getPropertyOutList();
        if (CollectionUtil.isEmpty(propertyOutList)){
            return "数据为空";
        }

        List<PropertyBasics> existPropertyList = propertyBasicsService.list(new LambdaQueryWrapper<PropertyBasics>()
                .eq(PropertyBasics::getStatus, FormStatusConstant.FINISH)
                .eq(PropertyBasics::getCompetentOrganization, competentOrganization));
        List<String> existOrgCodes = Optional.ofNullable(existPropertyList).orElse(new ArrayList<>()).stream().map(PropertyBasics::getOrgCode).collect(Collectors.toList());
        List<PropertyOut> transferDataList = list(new LambdaQueryWrapper<PropertyOut>()
                .eq(PropertyOut::getDataSource, TokenUtil.getTokenUserId()));
        Map<String, PropertyOut> transferDataMap = transferDataList.stream()
                .filter(propertyOut -> StringUtil.isNotBlank(propertyOut.getDataSourceId()))
                .collect(Collectors.toMap(PropertyOut::getDataSourceId, propertyOut -> propertyOut));
        List<PropertyOut> noApprovalList = list(new LambdaQueryWrapper<PropertyOut>().ne(PropertyOut::getStatus, FormStatusConstant.FINISH));
        List<String> noApprovalOrgCodeList = noApprovalList.stream()
                .map(PropertyOut::getAicOrgCode).collect(Collectors.toList());


        StringBuilder message = new StringBuilder();
        for (PropertyOut propertyOut : propertyOutList){
            String orgCode = propertyOut.getAicOrgCode();
            if (!existOrgCodes.contains(orgCode)){
                if (message.length() > 0){
                    message.append(",");
                }
                message.append("orgCode = " + orgCode + ", dataSourceId=" + propertyOut.getDataSourceId() +  "在最新记录表中不存在");
                continue;
            }
            if (CollectionUtil.isNotEmpty(transferDataMap) && transferDataMap.containsKey(propertyOut.getDataSourceId())){
                PropertyOut old = transferDataMap.get(propertyOut.getDataSourceId());
                if (!String.valueOf(FormStatusConstant.UNREVIEWED).equals(old.getStatus())
                        && !String.valueOf(FormStatusConstant.REJECT).equals(old.getStatus())){
                    message.append("orgCode = " + orgCode
                             + ", dataSourceId=" + propertyOut.getDataSourceId() + ", 该数据审批中或已审核");
                    continue;
                }
                propertyOut.setId(old.getId());
            }else if (CollectionUtil.isNotEmpty(noApprovalOrgCodeList) && noApprovalOrgCodeList.contains(orgCode)){
                message.append("orgCode = " + orgCode
                        + ", dataSourceId=" + propertyOut.getDataSourceId() + ", 该数据审批中或已审核");
            }
        }
        return message.toString();
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public boolean unitSaveList(PropertyInfoDTO propertyInfoDTO) {
        List<PropertyOut> propertyOutList = propertyInfoDTO.getPropertyOutList();
        List<PropertyBasics> existPropertyList = propertyBasicsService.list(new LambdaQueryWrapper<PropertyBasics>()
                .eq(PropertyBasics::getStatus, FormStatusConstant.FINISH).eq(PropertyBasics::getCompetentOrganization, TokenUtil.getCompetentOrganization()));
        Map<String, PropertyBasics> propertyBasicsMap = existPropertyList.stream().filter(propertyBasics -> StringUtil.isNotBlank(propertyBasics.getOrgCode()))
                .collect(Collectors.toMap(PropertyBasics::getOrgCode, propertyBasics -> propertyBasics));

        String tokenUserId = TokenUtil.getTokenUserId();
        String tokenOrgId = TokenUtil.getTokenOrgId();
        Map<String, String> recordMap = new HashMap<>();
        try {
            Page page = new Page(false, new PageData());
            List<PageData> recordList = propertyRecordDao.listPage(page);
            recordMap = recordList.stream()
                    .collect(Collectors.toMap(record -> record.getString("initialId"), record -> record.getString("id")));
        }catch (Exception e){
            log.error(ExceptionUtils.getFullStackTrace(e));
        }
        Date now = new Date();
        for (PropertyOut propertyOut : propertyOutList){
            propertyOut.setDataSource(tokenUserId);
            if (StringUtil.isBlank(propertyOut.getId())){
                propertyOut.setCreateTime(now);
            }
            if (propertyOut.getUpdateTime() == null){
                propertyOut.setUpdateTime(propertyOut.getCreateTime());
            }
            propertyOut.setOrgId(tokenOrgId);
            propertyOut.setStatus(String.valueOf(FormStatusConstant.UNREVIEWED));
            propertyOut.setFormType(String.valueOf(FormTypeConstant.PM_PROPERTYOUT_FORM));
            propertyOut.setInitialId(propertyBasicsMap.get(propertyOut.getAicOrgCode()).getId());
            if (recordMap.containsKey(propertyOut.getInitialId())){
                propertyOut.setProId(recordMap.get(propertyOut.getInitialId()));
            }

        }

        boolean result = saveOrUpdateBatch(propertyOutList);
        List<String> propertyIds = propertyOutList.stream().map(PropertyOut::getId).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(propertyIds)){
            transferFlowService.submit(propertyIds, FormTypeConstant.PM_PROPERTYOUT_FORM);
        }
        return result;
    }

    @Override
    public String ythSubmitBatch(String data) {
        YthResult ythResult = new YthResult();
        //成功的id集合
        List<String> successIds = new ArrayList<>();
        //失败的id集合
        List<String> failIds = new ArrayList<>();
        //失败的原因
        List<String> failReasons = new ArrayList<>();
        //将json字符串转换成list
        List<PropertyOut> dataList = JSON.parseArray(data, PropertyOut.class);
        if (CollectionUtil.isEmpty(dataList)){
            failReasons.add("数据为空");
            ythResult.setFailReason(StringUtils.join(failReasons, StringPool.COMMA));
            return JSON.toJSONString(ythResult);
        }
        //已登记的数据
        List<PropertyBasics> propertyBasicsList = propertyBasicsService.list(Wrappers.<PropertyBasics>lambdaQuery()
                .eq(PropertyBasics::getStatus, FormStatusConstant.FINISH)
                .isNotNull(PropertyBasics::getOrgCode)
                .eq(PropertyBasics::getCompetentOrganization, gzwProperties.getId()));
        List<PropertyRecord> allRecordList = propertyRecordService.list(Wrappers.<PropertyRecord>lambdaQuery()
                .eq(PropertyRecord::getCompetentOrganization, gzwProperties.getId()));
        Map<String, PropertyRecord> allRecordMap = allRecordList.stream().collect(Collectors.toMap(PropertyRecord::getId, Function.identity()));
        Map<String, PropertyBasics> propertyBasicsMap = propertyBasicsList.stream()
                .collect(Collectors.toMap(PropertyBasics::getOrgCode, Function.identity()));
        Map<String, PropertyBasics> propertyBasicsIdMap = propertyBasicsList.stream()
                .collect(Collectors.toMap(PropertyBasics::getId, Function.identity()));

        List<PropertyOut> propertyOutList = list(Wrappers.<PropertyOut>query().lambda()
                .eq(PropertyOut::getStatus, FormStatusConstant.FLOW));
        Set<String> cantOutOrgCodeList = propertyOutList.stream()
                .map(propertyOut -> propertyBasicsIdMap.getOrDefault(allRecordMap.getOrDefault(propertyOut.getProId(),
                        new PropertyRecord()).getInitialId(), new PropertyBasics()).getPropertyCode())
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        //查询获取可修改的老数据
        List<PropertyOut> oldList = list(new LambdaQueryWrapper<PropertyOut>()
                .in(PropertyOut::getStatus, Stream.of(FormStatusConstant.STASH,
                        FormStatusConstant.UNREVIEWED, FormStatusConstant.REJECT).collect(Collectors.toList())));
        Map<String, PropertyOut> oldOrgCodeMap = oldList.stream().collect(Collectors.toMap(PropertyOut::getAicOrgCode, Function.identity()));
        List<Org> orgList = orgService.getYthOrgList();
        Map<String, Org> dataSourceIdOrgMap = orgList.stream().collect(Collectors.toMap(Org::getDataSourceId, Function.identity()));

        List<PropertyOut> submitList = new ArrayList<>();
        Date now = DateUtil.now();
        for (PropertyOut propertyOut : dataList){
            if (!propertyBasicsMap.containsKey(propertyOut.getAicOrgCode())){
                failIds.add(propertyOut.getDataSourceId());
                failReasons.add(propertyOut.getDataSourceId() + "节点不存在");
                continue;
            }
            if (cantOutOrgCodeList.contains(propertyOut.getAicOrgCode())){
                failIds.add(propertyOut.getDataSourceId());
                failReasons.add(propertyOut.getDataSourceId() + "该企业注销流程中，不能再注销或修改");
                continue;
            }
            if (successIds.contains(propertyOut.getDataSourceId())){
                failIds.add(propertyOut.getDataSourceId());
                failReasons.add(propertyOut.getDataSourceId() + "id重复");
                continue;
            }

            successIds.add(propertyOut.getDataSourceId());
            if (oldOrgCodeMap.containsKey(propertyOut.getAicOrgCode())){
                propertyOut.setId(oldOrgCodeMap.get(propertyOut.getAicOrgCode()).getId());
            }
            if (dataSourceIdOrgMap.containsKey(propertyOut.getOrgId())){
                propertyOut.setOrgId(dataSourceIdOrgMap.get(propertyOut.getOrgId()).getId());
            }
            propertyOut.setCreateTime(now);
            propertyOut.setUpdateTime(now);
            PropertyRecord propertyRecord = propertyRecordService.getOne(Wrappers.<PropertyRecord>lambdaQuery()
                    .eq(PropertyRecord::getInitialId, propertyBasicsMap.get(propertyOut.getAicOrgCode()).getId())
                    .orderByDesc(PropertyRecord::getCreateTime)
                    .last("limit 1"));
            propertyOut.setProId(propertyRecord.getId());
            propertyOut.setFormType(String.valueOf(FormTypeConstant.PM_PROPERTYOUT_FORM));
            propertyOut.setDataSource(YthConstant.DATA_NINGBO);
            propertyOut.setStatus(String.valueOf(FormStatusConstant.UNREVIEWED));
            submitList.add(propertyOut);
        }

        if (CollectionUtil.isNotEmpty(submitList)){
            saveOrUpdateBatch(submitList);
            for (PropertyOut propertyOut : submitList){
                saveFile(propertyOut);
            }
        }
        ythResult.setSuccessIds(successIds);
        ythResult.setFailIds(failIds);
        ythResult.setFailReason(StringUtils.join(failReasons, StringPool.COMMA));
        //ythResult转换成json字符串
        return JSON.toJSONString(ythResult);
    }

    private void saveFile(PropertyOut entity){
        fileService.upYthFile(entity.getF1(), entity.getId(), "fOut1");
        fileService.upYthFile(entity.getF2(), entity.getId(), "fOut2");
        fileService.upYthFile(entity.getF3(), entity.getId(), "fOut3");
        fileService.upYthFile(entity.getF4(), entity.getId(), "fOut4");
        fileService.upYthFile(entity.getF5(), entity.getId(), "fOut5");
        fileService.upYthFile(entity.getF6(), entity.getId(), "fOut6");
        fileService.upYthFile(entity.getF7(), entity.getId(), "fOut7");
        fileService.upYthFile(entity.getF8(), entity.getId(), "fOut8");
        fileService.upYthFile(entity.getF9(), entity.getId(), "fOut9");
    }
}
